package alittlepond.gui;

import java.awt.Dimension;
import java.util.HashMap;
import java.util.Map;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import alittlepond.config.HasProperties;
import alittlepond.config.Property;

/**
 * I miss the ability to lay out properties in html-like forms. So there's this.
 * 
 * 
 * 
 * @author hopey
 *
 * @param <T> The particular property subclass that it uses.
 */

@SuppressWarnings("serial")
public class Form<T extends Property> extends JPanel{

	private HasProperties<T> target;
	private Map<T,Object> values = new HashMap<T, Object>();
	
	public static final Dimension FORM_ITEM_SIZE = new Dimension(120, 25);
	
	
	public Form(HasProperties<T> target) {
		this.target = target;
		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
		
		//Some default layout stuff. Can override these if you want.
		
		//
		setMaximumSize(new Dimension(200,2000));
		
		values.putAll(target.getProperties());
		
		for(T property : target.getPropertyDefinitions()) {
			
			JComponent formItem = getFormItem(property);
			//maybe this should go in the getFormItem method
//			formItem.setMaximumSize(FORM_ITEM_SIZE);
			
			JLabel label = new JLabel(property.getTitle());
			label.setLabelFor(formItem);
			
			JPanel formRow = new JPanel();
			
			formRow.setLayout(new BoxLayout(formRow, BoxLayout.LINE_AXIS));
			formRow.add(label);
			formRow.add(Box.createHorizontalGlue());
			formRow.add(formItem);

			add(formRow);
			
		}
		
		
		
	}
	
	
	private JComponent getFormItem(final T property) {
	
		JComponent theComponent;
		Object value = target.getProperty(property);
		System.out.println("Value: " + value);
//		This is done above via putall.
//		values.put(property, value);
		
		switch (property.getPropertyType()) {
		case BOOLEAN: {
			final JCheckBox cb = new JCheckBox();
			//TODO: some validation of the type here.
			//And null check.
			cb.getModel().setSelected((Boolean) property.getDefaultValue());
			
			cb.addChangeListener(new  ChangeListener() {@Override public void stateChanged(ChangeEvent arg0) {
				values.put(property,cb.getModel().isSelected());
				target.setProperty(property, cb.getModel().isSelected());
			}});
			
			
			theComponent = cb;
			
			break;
		}
		case INT: {
			final JSpinner sp = new JSpinner();
			int initValue = (Integer) value;
			int min = (Integer) property.getMinValue();
			int max = (Integer) property.getMaxValue();
			int step = (Integer) property.getStepSize();
			System.out.printf("val %d min %d max %d step %d", initValue, min,max,step);
			
			sp.setModel(new SpinnerNumberModel(initValue,min,max,step));
			sp.addChangeListener(new ChangeListener() {
				
				@Override
				public void stateChanged(ChangeEvent e) {
					values.put(property, sp.getValue());
					target.setProperty(property, sp.getValue());
				}
			});
			theComponent = sp;
			//TODO: mess around with models to do this right.
			break;
		}
		case DOUBLE: {
			final JSpinner sp = new JSpinner();
			double initValue = (Double) value;
			double min = (Double) property.getMinValue();
			double max = (Double) property.getMaxValue();
			double step = (Double) property.getStepSize();
			
			
			sp.setModel(new SpinnerNumberModel(initValue,min,max,step));
//			sp.setValue(value);
			sp.addChangeListener(new ChangeListener() {
				
				@Override
				public void stateChanged(ChangeEvent e) {
					values.put(property, sp.getValue());
					target.setProperty(property, sp.getValue());
				}
			});
			theComponent = sp;
			//TODO: mess around with models to do this right.
			break;
		}
			
//		case STRING: {
//			theComponent = new JTextField();
//			break;
//		}
		
		default:
			//TODO: implement all of them
			throw new RuntimeException();
		
		}
		
		
		/*
		 * I'd love to be able to call theComponent.addChangeHandler or similar, but there's no common superinterface.
		 */
		
		
		
		theComponent.setPreferredSize(FORM_ITEM_SIZE);
		theComponent.setMaximumSize(FORM_ITEM_SIZE);
		
		
		return theComponent;
	}
	
	
}
